﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace System.Collections.Generic
{

    public static class IEnumerableExtensions
    {
        //public static IEnumerable<TResult> Cast<TSource, TResult>(this IEnumerable<TSource> enumerable, Func<TSource, TResult> castMethod)
        //{
        //    if (enumerable == null) throw new NullReferenceException();
        //    List<TResult> resultList = new List<TResult>();
        //    foreach (TSource item in enumerable) resultList.Add(castMethod(item));
        //    return resultList;
        //}

        //public static IEnumerable<object> Cast<TSource>(this IEnumerable<TSource> enumerable, Func<TSource, object> castMethod)
        //{
        //    return IEnumerableExtensions.Cast<TSource, object>(enumerable, castMethod);
        //}

        public static bool Exists<TElement>(this IEnumerable<TElement> enumerable, Func<TElement, bool> predicate)
        {
            return enumerable.Count(predicate) != 0;
        }
    }

    public static class IEnumerableCompareExtensions
    {
        private class DelegateComparer<T, TIdentity> : IEqualityComparer<T>
        {
            private readonly Func<T, TIdentity> identitySelector;
            public DelegateComparer(Func<T, TIdentity> identitySelector)
            {
                this.identitySelector = identitySelector;
            }

            public bool Equals(T x, T y)
            {
                return Equals(identitySelector(x), identitySelector(y));
            }
            public int GetHashCode(T obj)
            {
                return identitySelector(obj).GetHashCode();
            }
        }

        public static IEnumerable<T> DistinctBy<T, TIdentity>(this IEnumerable<T> source, Func<T, TIdentity> identitySelector)
        {
            return source.Distinct(IEnumerableCompareExtensions.By(identitySelector));
        }

        public static IEqualityComparer<TSource> By<TSource, TIdentity>(Func<TSource, TIdentity> identitySelector)
        {
            return new DelegateComparer<TSource, TIdentity>(identitySelector);
        }

        public static IEnumerable<T> IntersectBy<T, TIdentity>(this IEnumerable<T> source, IEnumerable<T> second, Func<T, TIdentity> identitySelector)
        {
            return source.Intersect(second, IEnumerableCompareExtensions.By<T,TIdentity>(identitySelector));
        }
    }
}
